home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyc (Python 2.6) '''Provides support for defining keybindings and matching them to input events.''' __id__ = '$Id: keybindings.py 3971 2008-06-11 00:54:46Z joanied $' __version__ = '$Revision: 3971 $' __date__ = '$Date: 2008-06-10 20:54:46 -0400 (Tue, 10 Jun 2008) $' __copyright__ = 'Copyright (c) 2005-2008 Sun Microsystems Inc.' __license__ = 'LGPL' try: import gtk except ImportError: pass import pyatspi import debug import settings import orca_state from orca_i18n import _ _keysymsCache = { } _keycodeCache = { } def getAllKeysyms(keysym): '''Given a keysym, find all other keysyms associated with the key that is mapped to the given keysym. This allows us, for example, to determine that the key bound to KP_Insert is also bound to KP_0.''' if keysym not in _keysymsCache: _keysymsCache[keysym] = [ keysym] keyval = gtk.gdk.keyval_from_name(keysym) if keyval != 0: keymap = gtk.gdk.keymap_get_default() entries = keymap.get_entries_for_keyval(keyval) keycode = 0 if entries: for entry in entries: if entry[1] == 0: keycode = entry[0] break continue if keycode != 0: entries = keymap.get_entries_for_keycode(keycode) if entries: for entry in entries: keyval = entry[0] name = gtk.gdk.keyval_name(keyval) if name and name != keysym: _keysymsCache[keysym].append(name) continue return _keysymsCache[keysym] def getKeycode(keysym): """Converts an XKeysym string (e.g., 'KP_Enter') to a keycode that should match the event.hw_code for key events. This whole situation is caused by the fact that Solaris chooses to give us different keycodes for the same key, and the keypad is the primary place where this happens: if NumLock is not on, there is no telling the difference between keypad keys and the other navigation keys (e.g., arrows, page up/down, etc.). One, for example, would expect to get KP_End for the '1' key on the keypad if NumLock were not on. Instead, we get 'End' and the keycode for it matches the keycode for the other 'End' key. Odd. If NumLock is on, we at least get KP_* keys. So...when setting up keybindings, we say we're interested in KeySyms, but those keysyms are carefully chosen so as to result in a keycode that matches the actual key on the keyboard. This is why we use KP_1 instead of KP_End and so on in our keybindings. Arguments: - keysym: a string that is a valid representation of an XKeysym. Returns an integer representing a key code that should match the event.hw_code for key events. """ if not keysym: return 0 return _keycodeCache[keysym] def getModifierNames(mods): '''Gets the modifier names of a numeric modifier mask as a human consumable string. ''' text = '' if mods & settings.ORCA_MODIFIER_MASK: text += _('Orca') + '+' if mods & 128: text += _('Alt_R') + '+' if mods & 1 << pyatspi.MODIFIER_META3: text += _('Super') + '+' if mods & 1 << pyatspi.MODIFIER_META2: text += _('Meta2') + '+' if mods & settings.ALT_MODIFIER_MASK: text += _('Alt_L') + '+' if mods & settings.CTRL_MODIFIER_MASK: text += _('Ctrl') + '+' if mods & 1 << pyatspi.MODIFIER_SHIFTLOCK: text += _('Caps_Lock') + '+' if mods & settings.SHIFT_MODIFIER_MASK: text += _('Shift') + '+' return text class KeyBinding: '''A single key binding, consisting of a keycode, a modifier mask, and the InputEventHandler. ''' def __init__(self, keysymstring, modifier_mask, modifiers, handler, click_count = 1): """Creates a new key binding. Arguments: - keysymstring: the keysymstring - this is typically a string from /usr/include/X11/keysymdef.h with the preceding 'XK_' removed (e.g., XK_KP_Enter becomes the string 'KP_Enter'). - modifier_mask: bit mask where a set bit tells us what modifiers we care about (see pyatspi.MODIFIER_*) - modifiers: the state the modifiers we care about must be in for this key binding to match an input event (see also pyatspi.MODIFIER_*) - handler: the InputEventHandler for this key binding """ self.keysymstring = keysymstring self.modifier_mask = modifier_mask self.modifiers = modifiers self.handler = handler self.click_count = click_count self.keycode = None def matches(self, keycode, modifiers): '''Returns true if this key binding matches the given keycode and modifier state. ''' if not self.keycode: self.keycode = getKeycode(self.keysymstring) if self.keycode == keycode: result = modifiers & self.modifier_mask return result == self.modifiers return False class KeyBindings: '''Structure that maintains a set of KeyBinding instances. ''' def __init__(self): self.keyBindings = [] def __str__(self): result = '[\n' for keyBinding in self.keyBindings: result += ' [%x %x %s %d %s]\n' % (keyBinding.modifier_mask, keyBinding.modifiers, keyBinding.keysymstring, keyBinding.click_count, keyBinding.handler.description) result += ']' return result def add(self, keyBinding): '''Adds the given KeyBinding instance to this set of keybindings. ''' self.keyBindings.append(keyBinding) def remove(self, keyBinding): '''Removes the given KeyBinding instance from this set of keybindings. ''' for i in range(0, len(self.keyBindings)): if keyBinding == self.keyBindings[i]: del self.keyBindings[i] continue def removeByHandler(self, handler): '''Removes the given KeyBinding instance from this set of keybindings. ''' i = len(self.keyBindings) while i > 0: if self.keyBindings[i - 1].handler == handler: del self.keyBindings[i - 1] i = i - 1 def hasKeyBinding(self, newKeyBinding, typeOfSearch = 'strict'): '''Return True if keyBinding is already in self.keyBindings. The typeOfSearch can be: "strict": matches description, modifiers, key, and click count "description": matches only description. "keys": matches the modifiers, key, and modifier mask, and click count "keysNoMask": matches the modifiers, key, and click count ''' hasIt = False for keyBinding in self.keyBindings: if typeOfSearch == 'strict': if keyBinding.handler.description == newKeyBinding.handler.description and keyBinding.keysymstring == newKeyBinding.keysymstring and keyBinding.modifier_mask == newKeyBinding.modifier_mask and keyBinding.modifiers == newKeyBinding.modifiers and keyBinding.click_count == newKeyBinding.click_count: hasIt = True keyBinding.click_count == newKeyBinding.click_count if typeOfSearch == 'description': if keyBinding.handler.description == newKeyBinding.handler.description: hasIt = True keyBinding.handler.description == newKeyBinding.handler.description if typeOfSearch == 'keys': if keyBinding.keysymstring == newKeyBinding.keysymstring and keyBinding.modifier_mask == newKeyBinding.modifier_mask and keyBinding.modifiers == newKeyBinding.modifiers and keyBinding.click_count == newKeyBinding.click_count: hasIt = True keyBinding.click_count == newKeyBinding.click_count if typeOfSearch == 'keysNoMask': if keyBinding.keysymstring == newKeyBinding.keysymstring and keyBinding.modifiers == newKeyBinding.modifiers and keyBinding.click_count == newKeyBinding.click_count: hasIt = True keyBinding.click_count == newKeyBinding.click_count return hasIt def getInputHandler(self, keyboardEvent): '''Returns the input handler of the key binding that matches the given keycode and modifiers, or None if no match exists. ''' if not orca_state.activeScript: return None candidates = [] clickCount = orca_state.activeScript.getClickCount() for keyBinding in self.keyBindings: if keyBinding.matches(keyboardEvent.hw_code, keyboardEvent.modifiers): if keyBinding.modifier_mask == keyboardEvent.modifiers and keyBinding.click_count == clickCount: return keyBinding.handler candidates.append(keyBinding) continue keyBinding.click_count == clickCount candidates.sort(cmp = (lambda x, y: x.click_count - y.click_count), reverse = True) for candidate in candidates: if candidate.click_count <= clickCount: return candidate.handler def consumeKeyboardEvent(self, script, keyboardEvent): '''Attempts to consume the given keyboard event. If these keybindings have a handler for the given keyboardEvent, it is assumed the event will always be consumed. ''' consumed = False handler = self.getInputHandler(keyboardEvent) if handler: consumed = True if keyboardEvent.type == pyatspi.KEY_PRESSED_EVENT: try: handler.processInputEvent(script, keyboardEvent) debug.printException(debug.LEVEL_SEVERE) return consumed